package com.info.zhiduoduo.core.service.makeralipay;

import com.alipay.api.domain.ExtCardInfo;
import com.alipay.api.response.AlipayFundAccountbookQueryResponse;
import com.alipay.api.response.AlipayFundTransCommonQueryResponse;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.info.zhiduoduo.alipay.constant.AlipayAgreementStatusEnum;
import com.info.zhiduoduo.alipay.constant.AlipayIdentityEnum;
import com.info.zhiduoduo.alipay.constant.AlipayOrderEnum;
import com.info.zhiduoduo.alipay.constant.AlipayOrderStatusEnum;
import com.info.zhiduoduo.alipay.constant.AlipayPrincipalEnum;
import com.info.zhiduoduo.alipay.model.request.TransferModel;
import com.info.zhiduoduo.alipay.service.AliPayApiService;
import com.info.zhiduoduo.common.configs.DocConfig;
import com.info.zhiduoduo.common.constants.StatusMsg;
import com.info.zhiduoduo.common.constants.entrustmentproject.AlipayPrincipalAccountFlowType;
import com.info.zhiduoduo.common.exception.Asserts;
import com.info.zhiduoduo.common.exception.SmartException;
import com.info.zhiduoduo.common.utils.DateUtil;
import com.info.zhiduoduo.common.utils.FileUtil;
import com.info.zhiduoduo.common.utils.RandomUtil;
import com.info.zhiduoduo.common.utils.StringUtil;
import com.info.zhiduoduo.core.service.CoreEntrustProjectServcie;
import com.info.zhiduoduo.core.service.CoreInvoiceService;
import com.info.zhiduoduo.core.service.CoreMakerAlipayService;
import com.info.zhiduoduo.core.service.CoreProjectService;
import com.info.zhiduoduo.core.service.common.BaseService;
import com.info.zhiduoduo.repository.entity.entrustmentproject.EntrustmentProject;
import com.info.zhiduoduo.repository.entity.entrustmentproject.EntrustmentProjectItem;
import com.info.zhiduoduo.repository.entity.maker.MakerAlipayAccountBook;
import com.info.zhiduoduo.repository.entity.maker.MakerAlipayAccountOrder;
import com.info.zhiduoduo.repository.entity.maker.MakerAlipayAgreement;
import com.info.zhiduoduo.repository.entity.maker.MakerAlipayPrincipal;
import com.info.zhiduoduo.repository.entity.maker.MakerAlipayPrincipalFlow;
import com.info.zhiduoduo.repository.entity.maker.MakerAlipayPrincipalOrder;
import com.info.zhiduoduo.repository.entity.maker.MakerStudio;
import com.info.zhiduoduo.repository.mapper.maker.MakerAlipayAccountBookMapper;
import com.info.zhiduoduo.repository.mapper.maker.MakerAlipayAccountOrderMapper;
import com.info.zhiduoduo.repository.mapper.maker.MakerAlipayAgreementMapper;
import com.info.zhiduoduo.repository.mapper.maker.MakerAlipayMapper;
import com.info.zhiduoduo.repository.mapper.maker.MakerAlipayPrincipalFlowMapper;
import com.info.zhiduoduo.repository.mapper.maker.MakerAlipayPrincipalMapper;
import com.info.zhiduoduo.repository.mapper.maker.MakerAlipayPrincipalOrderMapper;

import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.util.BiConsumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.net.URL;
import java.util.Date;
import java.util.function.Consumer;

import javax.servlet.http.HttpServletResponse;

import lombok.extern.slf4j.Slf4j;

import static com.info.zhiduoduo.common.constants.StatusMsg.StatusMsg_233;
import static com.info.zhiduoduo.common.constants.StatusMsg.StatusMsg_241;

@Slf4j
@Service
public class CoreMakerAlipayServiceImpl extends BaseService implements CoreMakerAlipayService {

	@Autowired
	AliPayApiService aliPayApiService;
	@Autowired
	CoreProjectService coreProjectService;
	@Autowired
	CoreInvoiceService coreInvoiceService;
	@Autowired
	CoreEntrustProjectServcie coreEntrustProjectServcie;

	@Autowired
	MakerAlipayMapper makerAlipayMapper;
	@Autowired
	MakerAlipayPrincipalMapper makerAlipayPrincipalMapper;
	@Autowired
	MakerAlipayPrincipalFlowMapper makerAlipayPrincipalFlowMapper;
	@Autowired
	MakerAlipayAgreementMapper makerAlipayAgreementMapper;
	@Autowired
	MakerAlipayAccountBookMapper makerAlipayAccountBookMapper;
	@Autowired
	MakerAlipayPrincipalOrderMapper makerAlipayPrincipalOrderMapper;
	@Autowired
	MakerAlipayAccountOrderMapper makerAlipayAccountOrderMapper;

	@Autowired
	DocConfig docConfig;

	/**
	 * 获取 平台的ISV主体，目前是秀圣企业支付宝账号
	 */
	public AlipayPrincipalEnum getISVPrincipal() {
//		return AlipayPrincipalEnum.XIUSHENG;
		return null;
	}

	@Override
	public MakerAlipayPrincipal queryZddPrincipalAccount(int principalId) {
		AlipayPrincipalEnum principalEnum = AlipayPrincipalEnum.findById(principalId);
		AlipayPrincipalEnum isvPrincipalEnum = getISVPrincipal();
		MakerAlipayPrincipal alipayPrincipal = new MakerAlipayPrincipal().selectById(principalId);
		Asserts.notNull(alipayPrincipal);
		if (!StringUtil.equals(alipayPrincipal.getStatus(), AlipayAgreementStatusEnum.NORMAL.code)) {
			// 签约状态不对， 返回
			throw SmartException.of(StatusMsg_233);
		}
		AlipayFundAccountbookQueryResponse response = aliPayApiService.fundAccountBookQuery(alipayPrincipal.getAccountBookId(),
				alipayPrincipal.getAlipayAgreementNo(), isvPrincipalEnum);
		if (response != null && response.isSuccess()) {
			// 更新记账本信息， 包括可用余额
			ExtCardInfo cardInfo = response.getExtCardInfo();
			alipayPrincipal.setAvailableAmount(new BigDecimal(response.getAvailableAmount()))
					.setBankAccName(cardInfo.getBankAccName())
					.setCardBank(cardInfo.getCardBank())
					.setCardBranch(cardInfo.getCardBranch())
					.setCardDeposit(cardInfo.getCardDeposit())
					.setCardLocation(cardInfo.getCardLocation())
					.setCardNo(cardInfo.getCardNo())
					.setAccountBookStatus(cardInfo.getStatus())
					.updateById();
		}
		return alipayPrincipal;
	}

	@Override
	public AlipayFundTransUniTransferResponse transfer2Entrustee(int principalId, int targetUserId, BigDecimal amount, int projectId, int projectType) {
		AlipayPrincipalEnum isvPrincipalEnum = getISVPrincipal();
		int isvId = isvPrincipalEnum.id;
		// 委托方信息, 作为支付方
		AlipayPrincipalEnum alipayPrincipalEnum = AlipayPrincipalEnum.findById(principalId);
		Asserts.notEquals(alipayPrincipalEnum, AlipayPrincipalEnum.UNKOWN, StatusMsg_241);
		MakerAlipayPrincipal alipayPrincipal = new MakerAlipayPrincipal().selectById(alipayPrincipalEnum.id);

		MakerStudio makerStudio = new MakerStudio().selectById(targetUserId);
		MakerAlipayAgreement targetAlipayAgreement = makerAlipayAgreementMapper.getByIsvIdAndUserid(isvId, targetUserId);
		Asserts.notNull(targetAlipayAgreement, StatusMsg_233);
		MakerAlipayAccountBook targetAlipayAccountBook = makerAlipayAccountBookMapper.getByIsvIdAndUserid(isvId, targetUserId);
		Asserts.notNull(targetAlipayAccountBook, StatusMsg_233);
		// 创建转账订单
		String orderNo = RandomUtil.createRandomNo("TRANS_", "");
		MakerAlipayPrincipalOrder order = createPrincipalOrder(isvId, orderNo, alipayPrincipal).setType(
						AlipayOrderEnum.PRINCIPAL_TRANSFER.type)
				.setPayeeEntrusteeId(targetUserId)
				.setPayeeAccountBookId(targetAlipayAccountBook.getAccountBookId())
				.setPayeeAgreementNo(targetAlipayAgreement.getAlipayAgreementNo())
				.setAmount(amount)
				.setProjectId(projectId)
				.setProjectType(projectType)
				.setRemark("转账给【" + makerStudio.getUsername() + "】资金记账本")
				.setTitle("转账")
				.setState(AlipayOrderStatusEnum.CREATE.id);
		order.insert();

		// 订单支付信息
		TransferModel model = new TransferModel();
		model.setOrderNo(orderNo);
		model.setOrderTitle(order.getTitle());
		model.setTransAmount(amount);
		// 付款方信息, 基于记账本
		model.setAccountBookId(alipayPrincipal.getAccountBookId());
		model.setAlipayAgreementNo(alipayPrincipal.getAlipayAgreementNo());
		// 收款方信息
		TransferModel.AccountBook targetAccountBook = new TransferModel.AccountBook().setAccountBookId(
				targetAlipayAccountBook.getAccountBookId()).setAgreementNo(targetAlipayAgreement.getAlipayAgreementNo());
		TransferModel.PayeeInfo payeeInfo = new TransferModel.PayeeInfo().setIdentityEnum(AlipayIdentityEnum.ACCOUNT_BOOK_ID)
				.setAccountBook(targetAccountBook);
		model.setPayeeInfo(payeeInfo);
		AlipayFundTransUniTransferResponse response = aliPayApiService.fundTransUniTransferAllocation(model, isvPrincipalEnum);
		if (response != null && !response.isSuccess()) {
			order.setAlipayErrorCode(response.getSubCode()).setAlipayErrorMsg(response.getSubMsg()).updateById();
		}

		return response;
	}

	@Override
	public MakerAlipayPrincipalOrder createPrincipalOrder(int isvId, String orderNo, MakerAlipayPrincipal alipayPrincipal) {
		return new MakerAlipayPrincipalOrder().setIsvId(isvId)
				.setOrderNo(orderNo)
				.setAccountBookId(alipayPrincipal.getAccountBookId())
				.setPrincipalId(alipayPrincipal.getId());
	}

	/**
	 * 解冻之前被冻结的委托人主账户余额
	 *
	 * @param principalId 0, 取当前 平台配置的主体
	 * @param amount      被冻结的金额， 正数
	 * @return
	 */
	@Override
	public boolean unfrozonPrincipalAmount(int principalId, BigDecimal amount) {
//		if (principalId == 0) {
//			principalId = AlipayPrincipalEnum.XIUSHENG.id;
//		}
		if (amount == null || amount.doubleValue() <= 0) return false;
		if (makerAlipayPrincipalMapper.frozen(principalId, amount.negate())) {
			// 记录解冻流水
			MakerAlipayPrincipal alipayPrincipal = new MakerAlipayPrincipal().selectById(principalId);
			BigDecimal prevAmount = alipayPrincipal.getAvailableAmount();
			BigDecimal fronzenAmount = alipayPrincipal.getFrozenAmount();
			MakerAlipayPrincipalFlow flow = new MakerAlipayPrincipalFlow().setOrderNo(RandomUtil.createRandomNo("UNFROZEN_", ""))
					.setPrincipalId(principalId)
					.setAccountBookId(alipayPrincipal.getAccountBookId())
					.setType(AlipayPrincipalAccountFlowType.UNFROZEN)
					.setAmount(amount)
					.setPrevAmount(prevAmount)
					.setAfterAmount(prevAmount)
					.setPrevFrozenAmount(fronzenAmount)
					.setAfterFrozenAmount(fronzenAmount.subtract(amount))
					.setRemark("解冻")
					.setFlowTime(DateUtil.nowTime());
			flow.insert();
			return true;
		}
		return false;
	}

	@Override
	public AlipayFundTransUniTransferResponse principalPay(String orderNo, int projectId, int projectType, int principalId,
	                                                       BigDecimal amount,
	                                                       String orderTitle, AlipayIdentityEnum identityEnum, String payeeIdentity,
	                                                       String payeeName,
	                                                       BiConsumer<MakerAlipayPrincipalOrder, AlipayFundTransUniTransferResponse> doAfterPay) {
		AlipayPrincipalEnum isvPrincipalEnum = getISVPrincipal();
		int isvId = isvPrincipalEnum.id;
		MakerAlipayPrincipal principal = new MakerAlipayPrincipal().selectById(principalId);
		Asserts.notNull(principal, StatusMsg_241);

		// 新建订单支付信息
		String remark = "项目款" + amount + "元";
		MakerAlipayPrincipalOrder order = new MakerAlipayPrincipalOrder().setIsvId(isvId)
				.setOrderNo(orderNo)
				.setAccountBookId(principal.getAccountBookId())
				.setPrincipalId(principalId)
				.setType(AlipayOrderEnum.PRINCIPAL_PAY.type)
				.setProjectId(projectId)
				.setProjectType(projectType)
				.setPayeeEntrusteeId(null)
				.setAmount(amount)
				.setTitle(orderTitle)
				.setRemark(remark)
				.setState(AlipayOrderStatusEnum.CREATE.id);
		order.insert();

		TransferModel model = new TransferModel();
		model.setOrderNo(orderNo);
		model.setOrderTitle(orderTitle);
		// model.setOrderRemark(remark);
		model.setTransAmount(amount);
		// 付款方信息, 基于记账本
		model.setAccountBookId(principal.getAccountBookId());
		model.setAlipayAgreementNo(principal.getAlipayAgreementNo());
		// 收款方信息
		TransferModel.PayeeInfo payeeInfo = TransferModel.PayeeInfo.of(identityEnum, payeeIdentity, payeeName, "");
		model.setPayeeInfo(payeeInfo);
		AlipayFundTransUniTransferResponse response = aliPayApiService.fundTransUniTransfer(model, isvPrincipalEnum);
		if (response == null) {
			return response;
		} else if (response.isSuccess()) {
			order.setAlipayOrderNo(response.getOrderId()).setAlipayPayFundOrderId(response.getPayFundOrderId());
		} else {
			order.setAlipayErrorCode(response.getSubCode()).setAlipayErrorMsg(response.getSubMsg()).updateById();
		}

		// 处理后续业务
		if (doAfterPay != null) {
			doAfterPay.accept(order, response);
		}
		return response;
	}

	@Override
	public void handlePrincipalOrderQueryResponse(MakerAlipayPrincipalOrder order, AlipayFundTransCommonQueryResponse response,
	                                              Consumer<MakerAlipayPrincipalOrder> successFunction) {
		if (response == null) {
			log.info("查询委托人主体记账本充值订单状态, response为null, orderNo={}", order.getOrderNo());
			return;
		}
		if (response.isSuccess()) {
			AlipayOrderStatusEnum statusEnum = AlipayOrderStatusEnum.findByCode(response.getStatus());
			// 设置状态
			order.setState(statusEnum.id)
					.setAlipayStatus(response.getStatus())
					.setAlipayMsg(response.getMsg())
					.setAlipayErrorCode(response.getSubCode())
					.setAlipayErrorMsg(response.getSubMsg() + response.getFailReason());
			switch (statusEnum) {
				case SUCCESS:
					order.setAlipayOrderNo(response.getOrderId())
							.setAlipayPayFundOrderId(response.getPayFundOrderId())
							.setFinishTime(DateUtil.parseDate(response.getPayDate(), DateUtil.FORMAT_STYLE_1));
					if (successFunction != null) {
						successFunction.accept(order);
					}
					break;
				case CLOSED:
				case FAIL:
				case REFUND:
				case UNKOWN:
					order.setFinishTime(new Date());
					break;
				default:
					break;
			}

		} else {
			// 转账订单不存在的情况，超过5分钟以后处理
			long min = (order.getCreatetime().getTime() - new Date().getTime()) / 60 / 1000;
			if (StringUtil.equals(AlipayOrderStatusEnum.NOT_EXIST.name(), response.getSubCode())) {
				if (min > 5) {
					order.setState(AlipayOrderStatusEnum.NOT_EXIST.id);
				}
			} else {
				order.setState(AlipayOrderStatusEnum.FAIL.id);
			}
			// 查询失败,设置失败原因
			order.setAlipayStatus(response.getStatus())
					.setAlipayMsg(response.getMsg())
					.setAlipayErrorCode(response.getSubCode())
					.setAlipayErrorMsg(response.getSubMsg());
		}
		order.updateById();
	}

	@Override
	public void recordPrincipalPayFlow(MakerAlipayPrincipalOrder order) {
		// 转账成功，解冻被冻结的金额
		Integer principalId = order.getPrincipalId();
		BigDecimal amount = order.getAmount();
		MakerAlipayPrincipal alipayPrincipal = new MakerAlipayPrincipal().selectById(principalId);
		BigDecimal prevFronzenAmount = alipayPrincipal.getFrozenAmount();
		unfrozonPrincipalAmount(principalId, amount);

		// 重新获取新的冻结金额
		BigDecimal afterFrozenAmount = new MakerAlipayPrincipal().selectById(principalId).getFrozenAmount();
		// 记录转账流水
		BigDecimal prevAmount = alipayPrincipal.getAvailableAmount();
		int type = AlipayPrincipalAccountFlowType.PRINCIPAL_PAY;

		MakerAlipayPrincipalFlow principalFlow = new MakerAlipayPrincipalFlow().setOrderNo(order.getOrderNo())
				.setPrincipalId(principalId)
				.setAccountBookId(order.getAccountBookId())
				.setType(type)
				.setAmount(amount)
				.setPrevAmount(prevAmount)
				.setAfterAmount(prevAmount.subtract(amount))
				.setPrevFrozenAmount(prevFronzenAmount)
				.setAfterFrozenAmount(afterFrozenAmount)
				.setRemark(order.getRemark())
				.setFlowTime(order.getFinishTime());
		principalFlow.insert();
		// 重新刷新下记账本信息
		queryZddPrincipalAccount(alipayPrincipal.getId());
	}

	@Override
	public void downloadEreceiptAndSave(MakerAlipayAccountOrder order) throws Exception {

		EntrustmentProjectItem projectItem = new EntrustmentProjectItem().selectById(order.getProjectId());
		Asserts.notNull(projectItem, StatusMsg.StatusMSG_1101);
		EntrustmentProject entrustmentProject = new EntrustmentProject().selectById(projectItem.getImportId());
		Asserts.notNull(entrustmentProject, StatusMsg.StatusMSG_1101);

		String filePath = generateEntrustAlipayEreceiptFilePath(entrustmentProject.getId());
		String fileName = order.getId() + "_" + order.getPayeeName() + ".pdf";
		FileUtils.copyURLToFile(new URL(order.getReceiptDownloadUrl()), new File(filePath, fileName));

		order.setReceiptDownloaded(1).updateById();
	}

	/**
	 * 生成支付宝回单文件夹的路径
	 *
	 * @param entrustmentProjectId 导入的委托接单（创客团）大项目id
	 * @return
	 */
	private String generateEntrustAlipayEreceiptFilePath(int entrustmentProjectId) {
		return docConfig.getEntrustAlipayEreceiptFilePath() + File.separator + "entrustment_project_" + entrustmentProjectId;
	}

	@Override
	public void downloadEreceiptFile(HttpServletResponse response, int itemId) {
		EntrustmentProjectItem projectItem = new EntrustmentProjectItem().selectById(itemId);
		Asserts.notNull(projectItem, StatusMsg.StatusMSG_1101);
		EntrustmentProject entrustmentProject = new EntrustmentProject().selectById(projectItem.getImportId());
		Asserts.notNull(entrustmentProject, StatusMsg.StatusMSG_1101);
		MakerAlipayAccountOrder order = makerAlipayAccountOrderMapper.getOrderByprojectId(itemId);
		Asserts.notNull(order, StatusMsg.StatusMsg_1108);

		try {
			String filePath = generateEntrustAlipayEreceiptFilePath(entrustmentProject.getId());
			String fileName = order.getId() + "_" + order.getPayeeName() + ".pdf";
			File file = new File(filePath, fileName);
			FileUtil.downloadFile(response, file);
		} catch (Exception e) {
			returnResponse(response, StatusMsg.StatusMsg_1112);
		}
	}

	@Override
	public void downloadEreceiptZipFile(HttpServletResponse response, int projectId) {
		EntrustmentProject entrustmentProject = new EntrustmentProject().selectById(projectId);
		Asserts.notNull(entrustmentProject, StatusMsg.StatusMSG_1101);

		try {
			String zipName = "支付宝回单_" + entrustmentProject.getCompname() + "_" + entrustmentProject.getId() + "_" +
					DateUtil.getString(entrustmentProject.getCreatetime(), DateUtil.FORMAT_STYLE_5) + ".zip";
			FileUtil.createZip2Response(response, generateEntrustAlipayEreceiptFilePath(entrustmentProject.getId()), zipName);
		} catch (Exception e) {
			returnResponse(response, StatusMsg.StatusMsg_1112);
		}
	}
}
